package com.sl.plugin.step.db;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.bazaarvoice.jolt.Chainr;
import com.sl.core.utils.JsonUtil;
import com.sl.core.engine.meta.impl.AbstractProcessCompDescriptor;
import com.sl.core.engine.step.ProcessCompService;
import com.sl.core.engine.step.impl.AbstractProcessComp;
import com.sl.core.engine.utils.BeanUtil;
import lombok.SneakyThrows;
import org.anyline.data.param.ConfigStore;
import org.anyline.data.param.init.DefaultConfigStore;
import org.anyline.entity.Compare;
import org.anyline.entity.DataRow;
import org.anyline.entity.DataSet;
import org.anyline.service.AnylineService;
import org.noear.snack.ONode;

import java.util.List;
import java.util.Map;

/**
 *
 */
public class DbInsertUpdateComp extends AbstractProcessComp<Map<String, Object>, Map<String, Object>> implements ProcessCompService {


    public DbInsertUpdateComp(AbstractProcessCompDescriptor abstractProcessCompDescriptor) {
        super(abstractProcessCompDescriptor);
    }

    @SneakyThrows
    @Override
    public Map<String, Object> input(Map<String, Object> param) {
        Map<String, Object> attributeMap = meta.getAttributeMap();
        Map<String, Object> output = MapUtil.get(attributeMap, "output", Map.class);
        List<Map<String, Object>> conditionData = meta.getListMapAttr(output, "conditionData");
        String dataSourceId = BeanUtil.getStr(output, "dataSourceId");
        String schemaId = BeanUtil.getStr(output, "schemaId");
        String tableName = BeanUtil.getStr(output, "tableName");

        if (StrUtil.isBlank(dataSourceId)) {
            return null;
        }
        //构建删除条件
        //现在开始删除
        AnylineService transactionAnyLineService = getAnyLineService(dataSourceId,false);
        ConfigStore configStore = buildWhere(conditionData, param);


        String jolt = this.meta.getStrAttr("jolt");

        List chainrSpecJSON = JsonUtil.toList(jolt, Map.class);
        Chainr chainr = Chainr.fromSpec(chainrSpecJSON);

        Object transformedOutput = chainr.transform(param);

        Map<String, Object> paramMap = BeanUtil.convert(transformedOutput);


        DataRow dataRow = new DataRow();
        dataRow.putAll(paramMap);

        DataSet query = transactionAnyLineService.querys(tableName, configStore);

        //找到了走修改，没有是新增 todo 存在问题，要分隔出来 insert 的需要拿出来， update的需要拿出来
        if (CollUtil.isNotEmpty(query)) {
            long delete = transactionAnyLineService.update(tableName, dataRow, configStore);
            param.put("rows", delete);
        } else {
            long delete = transactionAnyLineService.insert(tableName, dataRow);
            param.put("rows", delete);
        }
        return param;
    }


    private ConfigStore buildWhere(List<Map<String, Object>> conditionData, Map<String, Object> param) {

        ConfigStore rootConfig = new DefaultConfigStore();

        ONode oNode = ONode.loadObj(param);

        ConfigStore lastPrevConfig = rootConfig;
        ConfigStore lastConfig = rootConfig;

        for (Map<String, Object> conditionDatum : conditionData) {
            String logicalOperator = MapUtil.getStr(conditionDatum, "logicalOperator");
            String leftBracket = MapUtil.getStr(conditionDatum, "leftBracket");
            String fieldCode = MapUtil.getStr(conditionDatum, "fieldCode");
            String relationalOperator = MapUtil.getStr(conditionDatum, "relationalOperator");
            String rightValue = MapUtil.getStr(conditionDatum, "rightValue");
            Boolean rightValueConstantFlag = MapUtil.getBool(conditionDatum, "rightValueConstantFlag");
            String rightBracket = MapUtil.getStr(conditionDatum, "rightBracket");
            Object value = rightValue;
            if (BooleanUtil.isFalse(rightValueConstantFlag) && StrUtil.isNotBlank(rightValue)) {
                value = oNode.select(rightValue).toObject();
            }

            if (StrUtil.isBlank(logicalOperator)) {
                logicalOperator = "and";
            }
            if (StrUtil.equals(leftBracket, "(")) {
                DefaultConfigStore def = new DefaultConfigStore();
                if (StrUtil.equals(logicalOperator, "and")) {
                    lastConfig.and(def);
                    lastPrevConfig = lastConfig;
                    lastConfig = def;
                } else if (StrUtil.equals(logicalOperator, "or")) {
                    lastConfig.or(def);
                    lastPrevConfig = lastConfig;
                    lastConfig = def;
                    logicalOperator = "and";
                }
            }

            if (StrUtil.equals(relationalOperator, "eq")) {
                if (StrUtil.equals(logicalOperator, "and")) {
                    lastConfig.and(fieldCode, value);
                } else if (StrUtil.equals(logicalOperator, "or")) {
                    lastConfig.or(fieldCode, value);
                }

            } else if (StrUtil.equals(relationalOperator, "notIn")) {

                if (StrUtil.equals(logicalOperator, "and")) {
                    lastConfig.and(Compare.NOT_IN, fieldCode, value);
                } else if (StrUtil.equals(logicalOperator, "or")) {
                    lastConfig.or(Compare.NOT_IN, fieldCode, value);
                }
            }
            if (StrUtil.equals(rightBracket, "(")) {
                DefaultConfigStore def = new DefaultConfigStore();
                lastConfig.and(def);
                lastPrevConfig = lastConfig;
                lastConfig = def;
            } else if (StrUtil.equals(rightBracket, ")")) {
                lastConfig = lastPrevConfig;
            }
        }

        return rootConfig;
    }
}
